package cn.tnar.yunpark;


import cn.tnar.yunpark.huasai.HuasaiMessageDecoder;
import cn.tnar.yunpark.huasai.HuasaiSensorMessageHandler;
import cn.tnar.yunpark.service.SensorEventDispatcher;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Created by zxin on 2016/5/25.
 */
@Component
public class SocketServer {
    public static Logger log = LoggerFactory.getLogger(SocketServer.class);
    private EventLoopGroup bossGroup = null;
    private EventLoopGroup workerGroup = null;
    private ChannelFuture channelFuture = null;
    private ServerBootstrap serverBootstrap = null;

    private SensorEventDispatcher dispatcher;

    @Autowired
    public SocketServer(SensorEventDispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }

    @Value("${tnar.netty.read-timeout}")
    int readTimeout = 10 * 60;    // 10 minutes

    @Value("${tnar.netty.port}")
    int port = 4700;

    @Value("${tnar.netty.so-timeout}")
    int timeout = 60000;

    @Value("${tnar.netty.num-boss-threads}")
    int nBossThreads = 2;

    @Value("${tnar.netty.num-worker-threads}")
    int nWorkerThreads = 4;


    public void server() {
        if (null != bossGroup || null != workerGroup) {
            return;
        }
        log.info("Socket Server init");

        bossGroup = new NioEventLoopGroup(nBossThreads);
        workerGroup = new NioEventLoopGroup(nWorkerThreads);
        try {
            serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
            serverBootstrap.option(ChannelOption.SO_TIMEOUT, timeout);
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline p = socketChannel.pipeline();
                    p.addLast("Logger", new LoggingHandler(LogLevel.DEBUG));
                    p.addLast(new ReadTimeoutHandler(readTimeout));
                    p.addLast(new HuasaiMessageDecoder());
                    p.addLast(new HuasaiSensorMessageHandler(dispatcher));
                }
            });
            channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("Socket Server init error.", e);
        } finally {
            if (null != workerGroup) {
                workerGroup.shutdownGracefully();
            }
            if (null != bossGroup) {
                bossGroup.shutdownGracefully();
            }
        }
    }

    public void stop() {
        if (null != workerGroup) {
            workerGroup.shutdownGracefully();
        }
        if (null != bossGroup) {
            bossGroup.shutdownGracefully();
        }
    }

}
